package net.jjjshop.front.service.lbt.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.jjjshop.common.constants.BrokerageRecordConstants;
import net.jjjshop.common.constants.ConfConstants;
import net.jjjshop.common.constants.SysConfConstants;
import net.jjjshop.common.entity.lbt.*;
import net.jjjshop.common.entity.supplier.SupplierUser;
import net.jjjshop.common.entity.user.User;
import net.jjjshop.common.entity.user.UserBill;
import net.jjjshop.common.mapper.lbt.UserExtractMapper;
import net.jjjshop.common.service.lbt.LbSysConfigService;
import net.jjjshop.common.service.lbt.LbUserWalletService;
import net.jjjshop.common.service.lbt.UserBillService;
import net.jjjshop.common.service.supplier.SupplierUserService;
import net.jjjshop.common.util.BigDecimalUtil;
import net.jjjshop.common.util.DateUtil;
import net.jjjshop.common.vo.dateLimitUtilVo;
import net.jjjshop.framework.common.exception.BusinessException;
import net.jjjshop.framework.core.util.RequestDetailThreadLocal;
import net.jjjshop.framework.shiro.vo.LoginUserRedisVo;
import net.jjjshop.framework.util.LoginUtil;
import net.jjjshop.front.mapper.lbt.LbUserExtractMapper;
import net.jjjshop.front.param.user.UserExtractRequest;
import net.jjjshop.front.service.lbt.LbUserBankService;
import net.jjjshop.front.service.lbt.LbUserExtractService;
import net.jjjshop.front.service.user.UserService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;

import static java.math.BigDecimal.ZERO;

@Service("LbUserExtractService")
public class LbUserExtractServiceImpl extends ServiceImpl<LbUserExtractMapper, UserExtractEntity> implements LbUserExtractService {


    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private LbSysConfigService sysConfigService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserBillService userBillService;
    @Autowired
    private LbUserBankService bankService;

    @Autowired
    private LbUserWalletService userWalletService;
    @Resource
    private UserExtractMapper dao;

    @Autowired
    private SupplierUserService supplierUserService;

    /**
     * 列表
     * @param request 请求参数
     * @author Mr.Zhang
     * @since 2020-05-11
     * @return List<UserExtract>
     */
    @Override
    public IPage<UserExtractEntity> getList(UserExtractSearchRequest request, Integer page, Integer limit) {
        Page<UserExtractEntity> pageUser = new Page<UserExtractEntity>(page, limit);
        //带 UserExtract 类的多条件查询
//        LambdaQueryWrapper<UserExtractEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//        if (!StringUtils.isBlank(request.getKeywords())) {
//            lambdaQueryWrapper.and(i -> i.
//                    or().like(UserExtractEntity::getWechat, request.getKeywords()).   //微信号
//                            or().like(UserExtractEntity::getRealName, request.getKeywords()). //名称
//                            or().like(UserExtractEntity::getBankCode, request.getKeywords()). //银行卡
//                            or().like(UserExtractEntity::getBankAddress, request.getKeywords()). //开户行
//                            or().like(UserExtractEntity::getAlipayCode, request.getKeywords()). //支付宝
//                            or().like(UserExtractEntity::getFailMsg, request.getKeywords()) //失败原因
//            );
//        }
//
//        //提现状态
//        if (request.getStatus() != null) {
//            lambdaQueryWrapper.eq(UserExtractEntity::getStatus, request.getStatus());
//        }
//
//        //提现方式
//        if (!StringUtils.isBlank(request.getExtractType())) {
//            lambdaQueryWrapper.eq(UserExtractEntity::getExtractType, request.getExtractType());
//        }
//
//        //时间范围
//        if (StringUtils.isNotBlank(request.getDateLimit())) {
//            dateLimitUtilVo dateLimit = DateUtil.getDateLimit(request.getDateLimit());
//            lambdaQueryWrapper.between(UserExtractEntity::getCreateTime, dateLimit.getStartTime(), dateLimit.getEndTime());
//        }
//
//        //按创建时间降序排列
//        lambdaQueryWrapper.orderByDesc(UserExtractEntity::getCreateTime, UserExtractEntity::getId);

//        IPage<UserExtractEntity> extractList = dao.selectPage(pageUser,lambdaQueryWrapper);
        if (StringUtils.isNotBlank(request.getDateLimit())) {
            dateLimitUtilVo dateLimit = DateUtil.getDateLimit(request.getDateLimit());
            request.setStartTime(dateLimit.getStartTime());
            request.setEndTime(dateLimit.getEndTime());
        }
        IPage<UserExtractEntity> extractList = dao.getListData(pageUser, request.getExtractType(),request.getStatus(), request.getStartTime(), request.getEndTime());

        return extractList;
    }

    @Override
    public IPage<UserExtractEntity> getUserList(Integer page, Integer limit) {
        Page<UserExtractEntity> pageUser = new Page<UserExtractEntity>(page, limit);
        //带 UserExtract 类的多条件查询
        LambdaQueryWrapper<UserExtractEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        lambdaQueryWrapper.eq(UserExtractEntity::getUid,LoginUtil.getUserId());

        //按创建时间降序排列
        lambdaQueryWrapper.orderByDesc(UserExtractEntity::getCreateTime, UserExtractEntity::getId);

        IPage<UserExtractEntity> extractList = dao.selectPage(pageUser,lambdaQueryWrapper);
        return extractList;
    }

    @Override
    public Boolean extractApply(UserExtractRequest request) {
        LoginUserRedisVo vo = LoginUtil.getLoginUserRedisVo();
        SupplierUser supplierUser = supplierUserService.getOne(new LambdaQueryWrapper<SupplierUser>()
                .eq(SupplierUser::getUserName, vo.getMobile()));
        if (null == supplierUser){
            throw new RuntimeException("非服务中心不能提现");
        }
        QueryWrapper<LbSysConfigEntity> sysQuery = new QueryWrapper<>();
        LbSysConfigEntity configServiceOne = sysConfigService.getOne(sysQuery);

        BigDecimal ten = configServiceOne.getUserCashMin();
        if (request.getExtractPrice().compareTo(ten) < 0) {
            throw new BusinessException(StrUtil.format("最低提现金额{}元", ten));
        }

        LbUserWalletEntity walle = userWalletService.getUserWalletInfo(vo.getUserId());
        User user = userService.getById(vo.getUserId());
        if(user == null ){
            throw new BusinessException(0, "未找到用户信息");
        }
        if (!user.getPayPass().equals(DigestUtils.md5Hex(request.getPayPass()))) throw new BusinessException(0, "支付密码错误");

        BigDecimal money = walle.getMoney();//可提现总金额
        if (money.compareTo(ZERO) < 1) {
            throw new BusinessException(0, "您当前没有金额可以提现");
        }
        BigDecimal extractPrice = request.getExtractPrice();
        if (money.compareTo(extractPrice) < 0) {
            throw new BusinessException(0, "你当前最多可提现 " + money + "元");
        }
        QueryWrapper<LbUserBankEntity> bankQuery = new QueryWrapper<>();
        bankQuery.eq("uid",user.getUserId());
        bankQuery.eq("id",request.getBankId());
        LbUserBankEntity bankServiceOne = bankService.getOne(bankQuery);
        if (ObjectUtil.isEmpty(bankServiceOne)){
            throw new BusinessException(0, "请先添加银行卡");
        }

        UserExtractEntity userExtract = new UserExtractEntity();
        BeanUtils.copyProperties(request, userExtract);
        userExtract.setUid(user.getUserId());
        userExtract.setBalance(money.subtract(request.getExtractPrice()));
        BigDecimal rate = configServiceOne.getUserCashFee();
        userExtract.setRate(rate);
        userExtract.setRealMoney(extractPrice);
        //扣除手续费后的实际到账金额
        if (rate.compareTo(ZERO) > 0){
            BigDecimal realMoney = BigDecimalUtil.subDouble(request.getExtractPrice(),BigDecimalUtil.mul(rate,extractPrice));
            userExtract.setRealMoney(realMoney);
        }

        userExtract.setRealName(bankServiceOne.getRealName());
        userExtract.setExtractType(request.getExtractType());
        userExtract.setBankCode(bankServiceOne.getBankCode());
        userExtract.setBankName(bankServiceOne.getBankName());


        Boolean execute = transactionTemplate.execute(e -> {
            // 保存提现记录
            save(userExtract);
            // 修改用户佣金
            userService.operationBalance(user.getUserId(), extractPrice, money, "sub");
            userService.operationCashMoney(user.getUserId(), extractPrice, user.getCashMoney(), "add");
            // 添加记录
            userBillService.saveBill("申请提现", ConfConstants.COMMISSION_TYPE,0,extractPrice,user.getUserId(), SysConfConstants.USER_BILL_TYPE_TX,0);
            return Boolean.TRUE;
        });
        return execute;
    }


    /**
     * 提现审核
     *
     * @param id          提现申请id
     * @param status      审核状态 -1 未通过 0 审核中 1 已提现
     * @param backMessage 驳回原因
     * @return 审核结果
     */
    @Override
    public Boolean updateStatus(Integer id, Integer status, String backMessage) {
        if (status == -1 && StringUtils.isBlank(backMessage))
            throw new RuntimeException("驳回时请填写驳回原因");

        UserExtractEntity userExtract = getById(id);
        if (ObjectUtil.isNull(userExtract)) {
            throw new RuntimeException("提现申请记录不存在");
        }
        if (userExtract.getStatus() != 0) {
            throw new RuntimeException("提现申请已处理过");
        }
        userExtract.setStatus(status);

        User user = userService.getById(userExtract.getUid());
        if (ObjectUtil.isNull(user)) {
            throw new RuntimeException("提现用户数据异常");
        }

        Boolean execute = false;

        userExtract.setUpdateTime(cn.hutool.core.date.DateUtil.date());
        // 拒绝
        if (status == -1) {//未通过时恢复用户总金额
            userExtract.setFailMsg(backMessage);
            // 添加提现申请拒绝佣金记录
            UserBrokerageRecord brokerageRecord = new UserBrokerageRecord();
            brokerageRecord.setUid(user.getUserId());
            brokerageRecord.setLinkId(userExtract.getId().toString());
            brokerageRecord.setLinkType(BrokerageRecordConstants.BROKERAGE_RECORD_LINK_TYPE_WITHDRAW);
            brokerageRecord.setType(BrokerageRecordConstants.BROKERAGE_RECORD_TYPE_ADD);
            brokerageRecord.setTitle(BrokerageRecordConstants.BROKERAGE_RECORD_TITLE_WITHDRAW_FAIL);
            brokerageRecord.setPrice(userExtract.getExtractPrice());
//            brokerageRecord.setBalance(user.getBrokeragePrice().add(userExtract.getExtractPrice()));
            brokerageRecord.setMark(StrUtil.format("提现申请拒绝返还佣金{}", userExtract.getExtractPrice()));
            brokerageRecord.setStatus(BrokerageRecordConstants.BROKERAGE_RECORD_STATUS_COMPLETE);
            brokerageRecord.setCreateTime(DateUtil.nowDateTime());

            execute = transactionTemplate.execute(e -> {
                // 返还佣金
                // userService.operationBrokerage(userExtract.getUid(), userExtract.getExtractPrice(), user.getBrokeragePrice(), "add");
                userWalletService.operationMoney(userExtract.getExtractPrice(), userExtract.getUid(), "add");
                userBillService.addBillRecord("提现申请拒绝返还佣金", ConfConstants.COMMISSION_TYPE,1,userExtract.getExtractPrice(),userExtract.getUid(),null);
                updateById(userExtract);

                return Boolean.TRUE;
            });
        }

        // 同意
        if (status == 1) {
            QueryWrapper<LbSysConfigEntity> sysQuery = new QueryWrapper<>();
            LbSysConfigEntity configServiceOne = sysConfigService.getOne(sysQuery);
            BigDecimal sqk = BigDecimalUtil.mul(userExtract.getExtractPrice(),new BigDecimal("0.06"));
            configServiceOne.setDividendPool(BigDecimalUtil.addDouble(configServiceOne.getDividendPool(),sqk));
            sysConfigService.updateById(configServiceOne);

            execute = transactionTemplate.execute(e -> {

                updateById(userExtract);

                return Boolean.TRUE;
            });
        }
        return execute;
    }

    @Override
    public Boolean updateExtract(Integer id, UserExtractRequest userExtractRequest) {
        UserExtractEntity userExtract = new UserExtractEntity();
        BeanUtils.copyProperties(userExtractRequest, userExtract);
        userExtract.setId(id);
        return updateById(userExtract);
    }


    /**
     * 提现总金额
     * 总佣金 = 已提现佣金 + 未提现佣金
     * 已提现佣金 = 用户成功提现的金额
     * 未提现佣金 = 用户未提现的佣金 = 可提现佣金 + 冻结佣金 = 用户佣金
     * 可提现佣金 = 包括解冻佣金、提现未通过的佣金 = 用户佣金 - 冻结期佣金
     * 待提现佣金 = 待审核状态的佣金
     * 冻结佣金 = 用户在冻结期的佣金，不包括退回佣金
     * 退回佣金 = 因退款导致的冻结佣金退回
     */
    @Override
    public BalanceResponse getBalance(String dateLimit) {
        String startTime = "";
        String endTime = "";
        if (StringUtils.isNotBlank(dateLimit)) {
            dateLimitUtilVo dateRage = DateUtil.getDateLimit(dateLimit);
            startTime = dateRage.getStartTime();
            endTime = dateRage.getEndTime();
        }
        userWalletService.getSum("money");

        // 已提现
        BigDecimal withdrawn = getWithdrawn(startTime, endTime);
        // 待提现(审核中)
        BigDecimal toBeWithdrawn = getWithdrawning(startTime, endTime);
        // 拒绝
        BigDecimal refuseWithdrawn = getRefuseWithdrawn(startTime, endTime);



        return new BalanceResponse(withdrawn, null, refuseWithdrawn, toBeWithdrawn);
    }

    @Override
    public void extractExport(UserExtractSearchRequest request, HttpServletResponse httpServletResponse) throws UnsupportedEncodingException {
        if (StringUtils.isNotBlank(request.getDateLimit())) {
            dateLimitUtilVo dateLimit = DateUtil.getDateLimit(request.getDateLimit());
          request.setStartTime(dateLimit.getStartTime());
          request.setEndTime(dateLimit.getEndTime());
        }
        if (StringUtils.isEmpty(request.getExtractType())){
            request.setExtractType(null);
        }
        if (StringUtils.isEmpty(request.getStartTime())){
            request.setStartTime(null);
        }
        if (StringUtils.isEmpty(request.getEndTime())){
            request.setEndTime(null);
        }
        List<UserExtractEntity> userExtractEntities = dao.queryList(request.getExtractType(), request.getStatus(), request.getStartTime(), request.getEndTime());

        ExcelWriter writer = ExcelUtil.getWriter();
        writer.addHeaderAlias("nickName", "账号昵称");
        writer.addHeaderAlias("realName", "姓名");
        writer.addHeaderAlias("bankName", "银行名称");
        writer.addHeaderAlias("bankCode", "银行卡号");
        writer.addHeaderAlias("bankAddress", "开户行地址");
        writer.addHeaderAlias("extractPrice", "提现金额");
        writer.addHeaderAlias("realMoney", "实际到账金额");
        writer.addHeaderAlias("status", "状态：-1失败0审核中1已提现");
        writer.addHeaderAlias("failMsg", "失败原因");
        writer.write(userExtractEntities, true);

        httpServletResponse.setContentType("application/vnd.ms-excel;charset=utf-8");
        //name是下载对话框的名称，不支持中文，想用中文名称需要进行utf8编码
        String excelName = "提现-" + cn.hutool.core.date.DateUtil.format(new Date(), "yyyyMMddHHmmss");
        excelName = URLEncoder.encode(excelName, "utf-8");
        httpServletResponse.setHeader("Content-Disposition", "attachment;filename=" + excelName + ".xls");

        ServletOutputStream excelOut = null;
        //将excel文件信息写入输出流，返回给调用者
        try {
            excelOut = httpServletResponse.getOutputStream();
            writer.flush(excelOut, true);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }
        IoUtil.close(excelOut);
    }


    public BigDecimal getWithdrawn(String startTime, String endTime) {
        return getSum(null, 1, startTime, endTime);
    }

    /**
     * 审核中总金额
     * @author Mr.Zhang
     * @since 2020-05-11
     * @return BalanceResponse
     */
    private BigDecimal getWithdrawning(String startTime, String endTime) {
        return getSum(null, 0, startTime, endTime);
    }
    /**
     * 审核未通过总金额
     */
    private BigDecimal getRefuseWithdrawn(String startTime, String endTime) {
        return getSum(null, -1, startTime, endTime);
    }


    /**
     * 根据状态获取总额
     * @return BigDecimal
     */
    private BigDecimal getSum(Integer userId, int status, String startTime, String endTime) {
        LambdaQueryWrapper<UserExtractEntity> lqw = Wrappers.lambdaQuery();
        if (null != userId) {
            lqw.eq(UserExtractEntity::getUid,userId);
        }
        lqw.eq(UserExtractEntity::getStatus,status);
        if (StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime)) {
            lqw.between(UserExtractEntity::getCreateTime, startTime, endTime);
        }
        List<UserExtractEntity> userExtracts = dao.selectList(lqw);
        BigDecimal sum = ZERO;
        if (CollUtil.isNotEmpty(userExtracts)) {
            sum = userExtracts.stream().map(UserExtractEntity::getExtractPrice).reduce(ZERO, BigDecimal::add);
        }
        return sum;
    }

}
